package spe.ui.editor;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.FileEditorInput;

import spe.model.spem.SPEMElement;
import spe.model.spem.SPERootElement;
import spe.model.notation.SPEMDiagram;
import spe.ui.editor.part.GraphicalEditPartFactory;
import spe.ui.editor.part.SPEOutlineEditPartFactory;
import spe.xml.SPEXmlProvider;

/**	@author: Dao Anh Vu
 * 	@last update: Feb 5, 2013
 * 
 * 	@description: This editor is used to open a diagram object only.
 *  If user opens an object that not in any diagram, the object will be
 *  shown in an property view.
 */
public class SPEMGraphEditor extends SPEEditor
{
	//public static String ID = SPEMGraphEditor.class.getName();
	public static String ID = "spe.ui.editor";
	
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException
	{
		if( !(input instanceof SPEMEditorInput) ){
			if(input instanceof FileEditorInput ) {
				SPEMEditorInput newInput = new SPEMEditorInput((FileEditorInput)input);
				input = newInput;
			}else
				throw new RuntimeException("[SPEMGraphEditor] Wrong editor input!!!!!!!!");
		}
		
		diagram = ((SPEMEditorInput)input).getModel();
		
		super.init(site, input);
		initResourceChangeListener();
		initPartName();
		
		//System.out.println(String.format("[SPEMGraphEditor] init finished!!!"));
	}
	
	private void initPartName()
	{
		IPath path;
		FileEditorInput fileInput = (FileEditorInput)getEditorInput();
		path = fileInput.getPath().removeLastSegments(1);
		path = path.removeFirstSegments(path.segmentCount() - 1);
		//System.out.println(String.format("[SPEMGraphEditor] Partname %s", path.lastSegment()));
		setPartName(path.lastSegment());
	}
	
	/*
	 * Listen to changes from resource.
	 * */
	private void initResourceChangeListener()
	{
		resourceChangeListener = new IResourceChangeListener(){
			public void resourceChanged(IResourceChangeEvent event)
			{
				handleResourceChangeEvent(event);
			}
		};
		
		getWorkspace().addResourceChangeListener(resourceChangeListener);
	}
		
	private void initGraphPage()
	{
		if(diagram != null){
			graphPage = new GraphEditorPage(this);
			addPage(0, graphPage, "Diagram");
		}
	}
	
	@Override
	public MyScrollingGraphicalViewer createGraphicalViewer()
	{
		return new MyScrollingGraphicalViewer(this){

			@Override
			protected void initEditPartFactory()
			{
				setEditPartFactory(new GraphicalEditPartFactory());
			}
			
		};
	}
	
	private void handleResourceChangeEvent(IResourceChangeEvent event)
	{
		if(event.getType() == IResourceChangeEvent.POST_CHANGE)
		{
			IFile file = ((IFileEditorInput)getEditorInput()).getFile();
			if(!file.exists())
				deleteModelFolder(file);
		}
	}
	
	private void deleteModelFolder(IFile file)
	{
		IWorkspace workspace = ((IFileEditorInput)getEditorInput()).getFile().getWorkspace();
		final IContainer modelFolder = (((IFileEditorInput)getEditorInput()).getFile().getWorkspace()).getRoot().getFolder(file.getFullPath().removeLastSegments(1));
		if (modelFolder != null && modelFolder.exists()) 
		{
			WorkspaceJob job = new WorkspaceJob("delete") 
			{
				public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException 
				{
					modelFolder.delete(true, null);
					return Status.OK_STATUS;
				}
			};
			job.setRule(workspace.getRuleFactory().deleteRule(modelFolder));
			job.schedule();
		}
	}

	@Override
	public String getContributorId() 
	{
		return getSite().getId();
	}

	@SuppressWarnings("restriction")
	@Override
	protected void createPages() 
	{
		super.createPages();
		loadModelFromSourcePage();
		if(((SPEMEditorInput)getEditorInput()).getModel() != null){
			initGraphPage();
		}
		
		setActivePage(0);
	}
	
	protected void addPage(int index, IEditorPart part, String label) 
	{
		try {
			addPage(index, part, getEditorInput());
			setPageText(index, label);
		} catch (PartInitException e) 
		{
			e.printStackTrace();
		}
	}
	
	@Override
	@SuppressWarnings({ "rawtypes" })
	public Object getAdapter(Class adapterClass)
	{
		Object adapter = null;
		if(adapterClass == CommandStack.class)
			adapter = getCommandStack();
		else if(adapterClass == GraphicalViewer.class)
			adapter = getGraphicalViewer();
		else
			return super.getAdapter(adapterClass);
		
		return adapter;
	}
	
	@Override
	public void doSave(IProgressMonitor monitor)
	{
		super.doSave(monitor);
		srcPage.doSave(monitor);
		
		if(graphPage != null)
			graphPage.doSave(monitor);
	}

	@Override
	public void doSaveAs() {
		//For this moment, I do not allow "save as" to be functioned
		//so we do nothing here
	}

	@Override
	public boolean isSaveAsAllowed(){
		return false;
	}
	
	private IWorkspace getWorkspace() {	
		return ((IFileEditorInput)getEditorInput()).getFile().getWorkspace();
	}
	
	public void dispose() {
		getWorkspace().removeResourceChangeListener(resourceChangeListener);
		super.dispose();
	}

	@Override
	protected SPEOutlineViewer createOutlineViewer() {
		//System.out.println(String.format("[SPEMGraphEditor] createOutlineViewer"));
		SPEOutlineViewer outlineViewer = new SPEOutlineViewer(this){

			@Override
			protected void initEditPartFactory() {
				getViewer().setEditPartFactory(new SPEOutlineEditPartFactory());
			}
		};
		return outlineViewer;
	}

	@Override
	protected SPEXmlProvider createContentProvider() {
		return (new SPEXmlProvider(getSPEMFactory(), this));
	}

	@Override
	protected SPEMDiagram getDiagram() {	
		if(diagram == null)
			diagram = (SPEMDiagram) getSPEMFactory().createElementById("spe.model.diagram.SPEMDiagram"); 
		return diagram;
	}
	
	public SPEXmlProvider getContentProvider()	{
		if(contentProvider == null)
			contentProvider = this.createContentProvider();
		return contentProvider;
	}

	@Override
	public String getEditorId() {
		// TODO Auto-generated method stub
		return SPEMGraphEditor.ID;
	}
	
	private IFile getContainingFile(SPEMElement element){
		if(element instanceof SPERootElement)
			return ((SPERootElement)element).getFile();
		else
			return getContainingFile(element.getParent());
	}
}
